<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>36.3. Searching an Index</title>
<link rel="stylesheet" href="dbstyle.css" type="text/css">
<meta name="generator" content="DocBook XSL Stylesheets V1.72.0">
<link rel="start" href="index.html" title="Programmer's Reference Guide">
<link rel="up" href="zend.search.lucene.html" title="Chapter 36. Zend_Search_Lucene">
<link rel="prev" href="zend.search.lucene.index-creation.html" title="36.2. Building Indexes">
<link rel="next" href="zend.search.lucene.query-language.html" title="36.4. Query Language">
<link rel="chapter" href="introduction.html" title="Chapter 1. Introduction to Zend Framework">
<link rel="chapter" href="zend.acl.html" title="Chapter 2. Zend_Acl">
<link rel="chapter" href="zend.auth.html" title="Chapter 3. Zend_Auth">
<link rel="chapter" href="zend.cache.html" title="Chapter 4. Zend_Cache">
<link rel="chapter" href="zend.config.html" title="Chapter 5. Zend_Config">
<link rel="chapter" href="zend.console.getopt.html" title="Chapter 6. Zend_Console_Getopt">
<link rel="chapter" href="zend.controller.html" title="Chapter 7. Zend_Controller">
<link rel="chapter" href="zend.currency.html" title="Chapter 8. Zend_Currency">
<link rel="chapter" href="zend.date.html" title="Chapter 9. Zend_Date">
<link rel="chapter" href="zend.db.html" title="Chapter 10. Zend_Db">
<link rel="chapter" href="zend.debug.html" title="Chapter 11. Zend_Debug">
<link rel="chapter" href="zend.dojo.html" title="Chapter 12. Zend_Dojo">
<link rel="chapter" href="zend.dom.html" title="Chapter 13. Zend_Dom">
<link rel="chapter" href="zend.exception.html" title="Chapter 14. Zend_Exception">
<link rel="chapter" href="zend.feed.html" title="Chapter 15. Zend_Feed">
<link rel="chapter" href="zend.filter.html" title="Chapter 16. Zend_Filter">
<link rel="chapter" href="zend.form.html" title="Chapter 17. Zend_Form">
<link rel="chapter" href="zend.gdata.html" title="Chapter 18. Zend_Gdata">
<link rel="chapter" href="zend.http.html" title="Chapter 19. Zend_Http">
<link rel="chapter" href="zend.infocard.html" title="Chapter 20. Zend_InfoCard">
<link rel="chapter" href="zend.json.html" title="Chapter 21. Zend_Json">
<link rel="chapter" href="zend.layout.html" title="Chapter 22. Zend_Layout">
<link rel="chapter" href="zend.ldap.html" title="Chapter 23. Zend_Ldap">
<link rel="chapter" href="zend.loader.html" title="Chapter 24. Zend_Loader">
<link rel="chapter" href="zend.locale.html" title="Chapter 25. Zend_Locale">
<link rel="chapter" href="zend.log.html" title="Chapter 26. Zend_Log">
<link rel="chapter" href="zend.mail.html" title="Chapter 27. Zend_Mail">
<link rel="chapter" href="zend.measure.html" title="Chapter 28. Zend_Measure">
<link rel="chapter" href="zend.memory.html" title="Chapter 29. Zend_Memory">
<link rel="chapter" href="zend.mime.html" title="Chapter 30. Zend_Mime">
<link rel="chapter" href="zend.openid.html" title="Chapter 31. Zend_OpenId">
<link rel="chapter" href="zend.paginator.html" title="Chapter 32. Zend_Paginator">
<link rel="chapter" href="zend.pdf.html" title="Chapter 33. Zend_Pdf">
<link rel="chapter" href="zend.registry.html" title="Chapter 34. Zend_Registry">
<link rel="chapter" href="zend.rest.html" title="Chapter 35. Zend_Rest">
<link rel="chapter" href="zend.search.lucene.html" title="Chapter 36. Zend_Search_Lucene">
<link rel="chapter" href="zend.server.html" title="Chapter 37. Zend_Server">
<link rel="chapter" href="zend.service.html" title="Chapter 38. Zend_Service">
<link rel="chapter" href="zend.session.html" title="Chapter 39. Zend_Session">
<link rel="chapter" href="zend.soap.html" title="Chapter 40. Zend_Soap">
<link rel="chapter" href="zend.test.html" title="Chapter 41. Zend_Test">
<link rel="chapter" href="zend.text.html" title="Chapter 42. Zend_Text">
<link rel="chapter" href="zend.timesync.html" title="Chapter 43. Zend_TimeSync">
<link rel="chapter" href="zend.translate.html" title="Chapter 44. Zend_Translate">
<link rel="chapter" href="zend.uri.html" title="Chapter 45. Zend_Uri">
<link rel="chapter" href="zend.validate.html" title="Chapter 46. Zend_Validate">
<link rel="chapter" href="zend.version.html" title="Chapter 47. Zend_Version">
<link rel="chapter" href="zend.view.html" title="Chapter 48. Zend_View">
<link rel="chapter" href="zend.xmlrpc.html" title="Chapter 49. Zend_XmlRpc">
<link rel="appendix" href="requirements.html" title="Appendix A. Zend Framework Requirements">
<link rel="appendix" href="coding-standard.html" title="Appendix B. Zend Framework Coding Standard for PHP">
<link rel="appendix" href="copyrights.html" title="Appendix C. Copyright Information">
<link rel="index" href="the.index.html" title="Index">
<link rel="subsection" href="zend.search.lucene.searching.html#zend.search.lucene.searching.query_building" title="36.3.1. Building Queries">
<link rel="subsection" href="zend.search.lucene.searching.html#zend.search.lucene.searching.results" title="36.3.2. Search Results">
<link rel="subsection" href="zend.search.lucene.searching.html#zend.search.lucene.searching.results-limiting" title="36.3.3. Limiting the Result Set">
<link rel="subsection" href="zend.search.lucene.searching.html#zend.search.lucene.searching.results-scoring" title="36.3.4. Results Scoring">
<link rel="subsection" href="zend.search.lucene.searching.html#zend.search.lucene.searching.sorting" title="36.3.5. Search Result Sorting">
<link rel="subsection" href="zend.search.lucene.searching.html#zend.search.lucene.searching.highlighting" title="36.3.6. Search Results Highlighting">
</head>
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
<div class="navheader"><table width="100%" summary="Navigation header">
<tr><th colspan="3" align="center">36.3. Searching an Index</th></tr>
<tr>
<td width="20%" align="left">
<a accesskey="p" href="zend.search.lucene.index-creation.html">Prev</a> </td>
<th width="60%" align="center">Chapter 36. Zend_Search_Lucene</th>
<td width="20%" align="right"> <a accesskey="n" href="zend.search.lucene.query-language.html">Next</a>
</td>
</tr>
</table></div>
<div class="sect1" lang="en">
<div class="titlepage"><div><div><h2 class="title" style="clear: both">
<a name="zend.search.lucene.searching"></a>36.3. Searching an Index</h2></div></div></div>
<div class="sect2" lang="en">
<div class="titlepage"><div><div><h3 class="title">
<a name="zend.search.lucene.searching.query_building"></a>36.3.1. Building Queries</h3></div></div></div>
<p>
            There are two ways to search the index. The first method uses
            query parser to construct a query from a string. The second is
            to programmatically create your own queries through the Zend_Search_Lucene API.
        </p>
<p>
        Before choosing to use the provided query parser, please consider
        the following:

            </p>
<div class="orderedlist"><ol type="1">
<li><p>
                        If you are programmatically creating a query string and then parsing
                        it with the query parser then you should consider building
                        your queries directly with the query API. Generally speaking, the query
                        parser is designed for human-entered text, not for program-generated text.
                    </p></li>
<li><p>
                        Untokenized fields are best added directly to queries and not through
                        the query parser. If a field's values are generated programmatically
                        by the application, then the query clauses for this field should also
                        be constructed programmatically.
                        An analyzer, which the query parser uses, is designed to convert
                        human-entered text to terms. Program-generated values, like dates,
                        keywords, etc., should be added with the query API.
                    </p></li>
<li><p>
                        In a query form, fields that are general text should use the query parser.
                        All others, such as date ranges, keywords, etc., are better added directly
                        through the query API. A field with a limited set of values that can be
                        specified with a pull-down menu should not be added to a query string
                        that is subsequently parsed but instead should be added as a TermQuery clause.
                    </p></li>
<li><p>
                        Boolean queries allow the programmer to logically combine two or more queries into new one.
                        Thus it's the best way to add additional criteria to a search defined by
                        a query string.
                    </p></li>
</ol></div>
<p>

        </p>
<p>
            Both ways use the same API method to search through the index:
        </p>
<pre class="programlisting">&lt;?php
require_once 'Zend/Search/Lucene.php';

$index = Zend_Search_Lucene::open('/data/my_index');

$index-&gt;find($query);
        </pre>
<p>
            The <code class="code">Zend_Search_Lucene::find()</code> method determines the input type automatically and
            uses the query parser to construct an appropriate Zend_Search_Lucene_Search_Query object
            from an input of type string.
        </p>
<p>
            It is important to note that the query parser uses the standard analyzer to tokenize separate parts of query string.
            Thus all transformations which are applied to indexed text are also applied to query strings.
        </p>
<p>
            The standard analyzer may transform the query string to lower case for case-insensitivity, remove stop-words, and stem among other transformations.
        </p>
<p>
            The API method doesn't transform or filter input terms in any way. It's therefore more suitable for
            computer generated or untokenized fields.
        </p>
<div class="sect3" lang="en">
<div class="titlepage"><div><div><h4 class="title">
<a name="zend.search.lucene.searching.query_building.parsing"></a>36.3.1.1. Query Parsing</h4></div></div></div>
<p>
                <code class="code">Zend_Search_Lucene_Search_QueryParser::parse()</code> method may be used to parse query strings
                into query objects.
            </p>
<p>
                This query object may be used in query construction API methods to combine user entered queries with
                programmatically generated queries.
            </p>
<p>
                Actually, in some cases it's the only way to search for values within untokenized fields:

                </p>
<pre class="programlisting">&lt;?php
$userQuery = Zend_Search_Lucene_Search_QueryParser::parse($queryStr);

$pathTerm  = new Zend_Search_Lucene_Index_Term('/data/doc_dir/' . $filename, 'path');
$pathQuery = new Zend_Search_Lucene_Search_Query_Term($pathTerm);

$query = new Zend_Search_Lucene_Search_Query_Boolean();
$query-&gt;addSubquery($userQuery, true /* required */);
$query-&gt;addSubquery($pathQuery, true /* required */);

$hits = $index-&gt;find($query);
                </pre>
<p>
            </p>
<p>
                <code class="code">Zend_Search_Lucene_Search_QueryParser::parse()</code> method also takes an optional encoding parameter,
                which can specify query string encoding:
            </p>
<pre class="programlisting">&lt;?php
$userQuery = Zend_Search_Lucene_Search_QueryParser::parse($queryStr, 'iso-8859-5');
            </pre>
<p>
            </p>
<p>
                If the encoding parameter is omitted, then current locale is used.
            </p>
<p>
                It's also possible to specify the default query string encoding with
                <code class="code">Zend_Search_Lucene_Search_QueryParser::setDefaultEncoding()</code> method:
                </p>
<pre class="programlisting">&lt;?php
Zend_Search_Lucene_Search_QueryParser::setDefaultEncoding('iso-8859-5');
...
$userQuery = Zend_Search_Lucene_Search_QueryParser::parse($queryStr);
                </pre>
<p>
            </p>
<p>
                <code class="code">Zend_Search_Lucene_Search_QueryParser::getDefaultEncoding()</code> returns the current default query
                string encoding (the empty string means "current locale").
            </p>
</div>
</div>
<div class="sect2" lang="en">
<div class="titlepage"><div><div><h3 class="title">
<a name="zend.search.lucene.searching.results"></a>36.3.2. Search Results</h3></div></div></div>
<p>
            The search result is an array of Zend_Search_Lucene_Search_QueryHit objects.  Each of these has
            two properties: <code class="code">$hit-&gt;document</code> is a document number within
            the index and <code class="code">$hit-&gt;score</code> is a score of the hit in
            a search result. The results are ordered by score (descending from highest score).
        </p>
<p>
            The Zend_Search_Lucene_Search_QueryHit object also exposes each field of the Zend_Search_Lucene_Document found in the search 
            as a property of the hit.  In the following example, a hit is returned with two fields from the corresponding document: title and author.
        </p>
<pre class="programlisting">&lt;?php
require_once('Zend/Search/Lucene.php');

$index = Zend_Search_Lucene::open('/data/my_index');

$hits = $index-&gt;find($query);

foreach ($hits as $hit) {
    echo $hit-&gt;score;
    echo $hit-&gt;title;
    echo $hit-&gt;author;
}
        </pre>
<p>
            Stored fields are always returned in UTF-8 encoding.
        </p>
<p>
            Optionally, the original Zend_Search_Lucene_Document object can be returned from the
            Zend_Search_Lucene_Search_QueryHit.

            You can retrieve stored parts of the document by using the <code class="code">getDocument()</code>
            method of the index object and then get them by
            <code class="code">getFieldValue()</code> method:
        </p>
<pre class="programlisting">&lt;?php
require_once 'Zend/Search/Lucene.php';

$index = Zend_Search_Lucene::open('/data/my_index');

$hits = $index-&gt;find($query);
foreach ($hits as $hit) {
    // return Zend_Search_Lucene_Document object for this hit
    echo $document = $hit-&gt;getDocument();

    // return a Zend_Search_Lucene_Field object
    // from the Zend_Search_Lucene_Document
    echo $document-&gt;getField('title');

    // return the string value of the Zend_Search_Lucene_Field object
    echo $document-&gt;getFieldValue('title');

    // same as getFieldValue()
    echo $document-&gt;title;
}
        </pre>
<p>
        The fields available from the Zend_Search_Lucene_Document object are determined at
        the time of indexing.  The document fields are either indexed, or
        index and stored, in the document by the indexing application
        (e.g. LuceneIndexCreation.jar).
        </p>
<p>
        Note that the document identity ('path' in our example) is also stored
        in the index and must be retrieved from it.
        </p>
</div>
<div class="sect2" lang="en">
<div class="titlepage"><div><div><h3 class="title">
<a name="zend.search.lucene.searching.results-limiting"></a>36.3.3. Limiting the Result Set</h3></div></div></div>
<p>
            The most computationally expensive part of searching is score calculation. It may take several seconds for large result sets (tens of thousands of hits).
        </p>
<p>
            Zend_Search_Lucene gives the possibility to limit result set size with <code class="code">getResultSetLimit()</code> and
            <code class="code">setResultSetLimit()</code> methods:
            </p>
<pre class="programlisting">&lt;?php
$currentResultSetLimit = Zend_Search_Lucene::getResultSetLimit();

Zend_Search_Lucene::setResultSetLimit($newLimit);
            </pre>
<p>
            The default value of 0 means 'no limit'.
        </p>
<p>
            It doesn't give the 'best N' results, but only the 'first N'<sup>[<a name="id3082856" href="#ftn.id3082856">7</a>]</sup>.
        </p>
</div>
<div class="sect2" lang="en">
<div class="titlepage"><div><div><h3 class="title">
<a name="zend.search.lucene.searching.results-scoring"></a>36.3.4. Results Scoring</h3></div></div></div>
<p>
            Zend_Search_Lucene uses the same scoring algorithms as Java Lucene.
            All hits in the search result are ordered by score by default. Hits with greater score come first, and
            documents having higher scores should match the query more precisely than documents having lower scores.
        </p>
<p>
            Roughly speaking, search hits that contain the searched term or phrase more frequently
            will have a higher score.
        </p>
<p>
            A hit's score can be retrieved by accessing the <code class="code">score</code> property of the hit:
        </p>
<pre class="programlisting">&lt;?php
$hits = $index-&gt;find($query);

foreach ($hits as $hit) {
    echo $hit-&gt;id;
    echo $hit-&gt;score;
}
        </pre>
<p>
            The Zend_Search_Lucene_Search_Similarity class is used to calculate the score for each hit.
            See <a href="zend.search.lucene.extending.html#zend.search.lucene.extending.scoring" title="36.7.3. Scoring Algorithms">Extensibility. Scoring Algorithms</a> section for details.
        </p>
</div>
<div class="sect2" lang="en">
<div class="titlepage"><div><div><h3 class="title">
<a name="zend.search.lucene.searching.sorting"></a>36.3.5. Search Result Sorting</h3></div></div></div>
<p>
            By default, the search results are ordered by score. The programmer can change this behavior by setting a sort field (or a list of fields), sort type
            and sort order parameters.
        </p>
<p>
            <code class="code">$index-&gt;find()</code> call may take several optional parameters:
            </p>
<pre class="programlisting">&lt;?php
$index-&gt;find($query [, $sortField [, $sortType [, $sortOrder]]] [, $sortField2 [, $sortType [, $sortOrder]]] ...);
            </pre>
<p>
        </p>
<p>
             A name of stored field by which to sort result should be passed as the <code class="code">$sortField</code> parameter.
        </p>
<p>
            <code class="code">$sortType</code> may be omitted or take the following enumerated values:
            <code class="code">SORT_REGULAR</code> (compare items normally- default value),
            <code class="code">SORT_NUMERIC</code> (compare items numerically),
            <code class="code">SORT_STRING</code> (compare items as strings).
        </p>
<p>
            <code class="code">$sortOrder</code> may be omitted or take the following enumerated values:
            <code class="code">SORT_ASC</code> (sort in ascending order- default value),
            <code class="code">SORT_DESC</code> (sort in descending order).
        </p>
<p>
            Examples:
            </p>
<pre class="programlisting">&lt;?php
$index-&gt;find($query, 'quantity', SORT_NUMERIC, SORT_DESC);
            </pre>
<p>
            </p>
<pre class="programlisting">&lt;?php
$index-&gt;find($query, 'fname', SORT_STRING, 'lname', SORT_STRING);
            </pre>
<p>
            </p>
<pre class="programlisting">&lt;?php
$index-&gt;find($query, 'name', SORT_STRING, 'quantity', SORT_NUMERIC, SORT_DESC);
            </pre>
<p>
        </p>
<p>
            Please use caution when using a non-default search order;
            the query needs to retrieve documents completely from an index, which may dramatically reduce search performance.
        </p>
</div>
<div class="sect2" lang="en">
<div class="titlepage"><div><div><h3 class="title">
<a name="zend.search.lucene.searching.highlighting"></a>36.3.6. Search Results Highlighting</h3></div></div></div>
<p>
            <code class="code">Zend_Search_Lucene_Search_Query::highlightMatches()</code> method allows the developer to highlight HTML document terms
            in the context of a search query:
            </p>
<pre class="programlisting">&lt;?php
$query = Zend_Search_Lucene_Search_QueryParser::parse($queryStr);
$hits = $index-&gt;find($query);
...
$highlightedHTML = $query-&gt;highlightMatches($sourceHTML);
            </pre>
<p>
        </p>
<p>
            <code class="code">highlightMatches()</code> method utilizes <code class="code">Zend_Search_Lucene_Document_Html</code> class
            (see <a href="zend.search.lucene.html#zend.search.lucene.index-creation.html-documents" title="36.1.4. HTML documents">HTML documents section</a> for details)
            for HTML processing, so it has the same requirements for HTML source.
        </p>
</div>
<div class="footnotes">
<br><hr width="100" align="left">
<div class="footnote"><p><sup>[<a name="ftn.id3082856" href="#id3082856">7</a>] </sup>Returned hits are still ordered by score or by the the specified order, if given.</p></div>
</div>
</div>
<div class="navfooter"><table width="100%" summary="Navigation footer">
<tr>
<td width="40%" align="left">
<a accesskey="p" href="zend.search.lucene.index-creation.html">Prev</a> </td>
<td width="20%" align="center"><a accesskey="u" href="zend.search.lucene.html">Up</a></td>
<td width="40%" align="right"> <a accesskey="n" href="zend.search.lucene.query-language.html">Next</a>
</td>
</tr>
<tr>
<td width="40%" align="left" valign="top">36.2. Building Indexes </td>
<td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td>
<td width="40%" align="right" valign="top"> 36.4. Query Language</td>
</tr>
</table></div>
<div class="revinfo"></div>
</body>
</html>
